Переход от последовательного программирования на ЦП к программированию на видеокарте требует смены парадигмы: от итерации по элементам к выполнению по блокам. Больше не воспринимаем данные как поток скаляров, а как совокупности «блоков», запланированных для насыщения пропускной способности аппаратного обеспечения.
1. Ограниченность памятью против вычислительной ограниченности
Ограничение производительности ядра определяется соотношением количества математических операций к количеству обращений к памяти. Сложение векторов часто ограничено памятью потому что оно выполняет только одну операцию сложения на каждые три обращения к памяти (2 загрузки, 1 сохранение). Аппаратное обеспечение тратит больше времени на ожидание данных из ОЗУ, чем на вычисления.
2. Роль параметра BLOCK_SIZE
BLOCK_SIZE определяет степень детализации параллелизма. Если он слишком мал, мы недостаточно используем широкие исполнительные каналы видеокарты. Оптимальный размер гарантирует достаточный объем «работы в полете» для насыщения шины памяти.
3. Скрытие задержек через занятость
Занятость — это количество активных блоков на видеокарте. Хотя это не конечная цель, она позволяет планировщику заменить один блок другим для выполнения вычислений, пока другой ждет получения данных из видеопамяти с высокой задержкой.
4. Использование аппаратных ресурсов
Чтобы максимизировать производительность, необходимо согласовать наш BLOCK_SIZE с правилами объединения памяти архитектуры видеокарты, обеспечивая, чтобы последовательные потоки обращались к последовательным адресам памяти.